package cn.ydxiaoshuai.modules.controller;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.ydxiaoshuai.common.constant.ApiCodeConts;
import cn.ydxiaoshuai.common.system.base.controller.ApiRestController;
import cn.ydxiaoshuai.common.util.RedisUtil;
import cn.ydxiaoshuai.common.util.oConvertUtils;
import cn.ydxiaoshuai.modules.conts.LogTypeConts;
import cn.ydxiaoshuai.modules.liteuser.entity.LiteUserInfo;
import cn.ydxiaoshuai.modules.liteuser.service.ILiteUserInfoService;
import cn.ydxiaoshuai.modules.util.ApiBeanUtil;
import cn.ydxiaoshuai.modules.weixin.po.ApiWxJSCODE2SESSIONResponseBean;
import cn.ydxiaoshuai.modules.weixin.po.wxlite.WXBind;
import cn.ydxiaoshuai.modules.weixin.po.wxlite.WxAuthRequestBean;
import cn.ydxiaoshuai.modules.weixin.po.wxlite.WxLoginResponseBean;
import cn.ydxiaoshuai.modules.weixin.util.AesCbcUtil;
import cn.ydxiaoshuai.modules.weixin.util.WXAPI;
import cn.ydxiaoshuai.modules.weixin.util.WXUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpSession;


/**
 * @author 小帅丶
 * @className WxLiteRestController
 * @Description 小程序所需接口
 * @Date 2020年4月30日14:00:36
 **/
@Controller
@RequestMapping(value = "/rest/wxlite")
@Slf4j
@Scope("prototype")
@Api(tags = "小程序API")
public class WxLiteRestController extends ApiRestController {
    @Autowired
    private WXUtil wxUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ApiBeanUtil apiBeanUtil;
    @Autowired
    private ILiteUserInfoService userInfoService;

    //掌心小程序APPID
    private static String APPID ="wx83b10d1a7b8d2310";


    /**
     * oauth微信小程序授权V1
     * @return ResponseEntity
     */
    @ApiOperation(value = "微信小程序授权V1-API", notes = "微信小程序授权V1-API")
    @ApiImplicitParams({
            @ApiImplicitParam(required = true, name = "code", value = "微信小程序返回的code"),
            @ApiImplicitParam(required = true, name = "appid", value = "微信小程序appid"),
    })
    @RequestMapping(value = "/v1/wx_login", method = {RequestMethod.POST, RequestMethod.GET})
    public ResponseEntity<Object> wxLogin() {
        WXBind bean = new WXBind();
        //接收参数微信小程序V1
        HttpSession httpSession = request.getSession();
        String code = ServletRequestUtils.getStringParameter(request, "code","");
        log.info("WJSDXZS授权V1-{}", code);
        param = "code=" + code;
        try {

                if (null != code && !"".equals(code)) {
                    log.info("WXXCX授权V1-code去换openid");

                    //根据code换取openId
                    String url = WXAPI.JSCODE2SESSION_URL.replace("APPID", "wx83b10d1a7b8d2310").
                            replace("SECRET","8f9dcf7dec99de8267ef37749638c026").replace("JSCODE", code);
                    String result = HttpUtil.get(url);

                    log.info("result = " + result);
                    ApiWxJSCODE2SESSIONResponseBean oa = JSONObject.parseObject(result, ApiWxJSCODE2SESSIONResponseBean.class);
                    log.info("V1-wx_login-getOpenid = " + oa.getOpenid());

                    //如果为空证明为第一次访问
                    if (null != httpSession.getAttribute("openid")) {
                        String openid = httpSession.getAttribute("openid").toString();
                        //不为空则直接获取openid进行业务处理
                        bean = apiBeanUtil.getIsRegister(openid,code);
                    }

                    if (null != oa) {
                        if (0 != oa.getErrcode()) {
                            if (oa.getErrcode() == 40029) {
                                bean.fail("code 无效", 40029);
                            }
                            if (oa.getErrcode() == -1) {
                                bean.fail("系统繁忙，此时请开发者稍候再试", -1);
                            }
                            if (oa.getErrcode() == 45011) {
                                bean.fail("频率限制，每个用户每分钟100次", 45011);
                            }
                            if (oa.getErrcode() == 40163) {
                                bean.fail("code已经被使用", 40163);
                            }
                        } else {
                            if (null != oa.getOpenid()) {
                                httpSession.setAttribute("openid", oa.getOpenid());
                                bean = apiBeanUtil.getIsRegister(oa.getOpenid(),code);
                                redisUtil.set(oa.getOpenid(), oa.getSession_key());
                            }
                        }
                    }
                } else {
                    bean.error("系统错误，稍后再试");
                }

        } catch (Exception e) {
            errorMsg = e.getMessage();
            bean.error(ApiCodeConts.MESSAGE_ERROR);
        }
        //耗时
        timeConsuming = String.valueOf(System.currentTimeMillis() - startTime);
        //响应的内容
        beanStr = JSON.toJSONString(bean);
        apiBeanUtil.putLog(bean.getLog_id(), timeConsuming, beanStr, ip, param,requestURI, errorMsg, LogTypeConts.WX_LOGIN,bean.getData().getUserId(),userAgent);
        return new ResponseEntity<Object>(beanStr, httpHeaders, HttpStatus.OK);
    }


    /**
     * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
     * @param iv            加密算法的初始向量
     * @param signature     使用 sha1( rawData + sessionkey ) 得到字符串，用于校验用户信息
     * @param hasUserInfo   是否授权过标识 不为空
     * @param openid        wx.login 得到的openid
     * @param rawData       不包括敏感信息的原始数据字符串，用于计算签名
     * @param wx_type       用户类型
     * @param userType      用户入口类型
     * @param userId        用户ID
     * @param account_code  公众号编码
     * @return org.springframework.http.ResponseEntity<java.lang.Object>
     * @Description 解密授权的信息
     * @Author 小帅丶
     * @Date 2020年4月1日18:11:06
     **/
    @ApiOperation(value = "微信小程序解密数据API", notes = "微信小程序解密数据API")
    @RequestMapping(value = "/v1/decrypt", method = {RequestMethod.POST})
    @ApiImplicitParams({
            @ApiImplicitParam(required = true, name = "encryptedData", value = "包括敏感数据在内的完整用户信息的加密数据"),
            @ApiImplicitParam(required = true, name = "iv", value = "加密算法的初始向量"),
            @ApiImplicitParam(required = true, name = "signature", value = "使用 sha1( rawData + sessionkey ) 得到字符串"),
            @ApiImplicitParam(required = true, name = "hasUserInfo", value = "是否授权过标识"),
            @ApiImplicitParam(required = true, name = "openid", value = "openid"),
            @ApiImplicitParam(required = true, name = "rawData", value = "不包括敏感信息的原始数据字符串"),
            @ApiImplicitParam(required = true, name = "wx_type", value = "用户类型"),
            @ApiImplicitParam(required = true, name = "userType", value = "用户入口类型"),
            @ApiImplicitParam(required = true, name = "userId", value = "用户ID"),
            @ApiImplicitParam(required = true, name = "account_code", value = "用户ID")
    })
    public ResponseEntity<Object> wxDecryptInfo(@RequestParam(name = "encryptedData", defaultValue = "", required = false) String encryptedData,
                                                @RequestParam(name = "iv", defaultValue = "") String iv,
                                                @RequestParam(name = "signature", defaultValue = "") String signature,
                                                @RequestParam(name = "hasUserInfo", defaultValue = "") boolean hasUserInfo,
                                                @RequestParam(name = "openid", defaultValue = "") String openid,
                                                @RequestParam(name = "rawData", defaultValue = "") String rawData,
                                                @RequestParam(name = "wx_type", defaultValue = "") String wx_type,
                                                @RequestParam(name = "userType", defaultValue = "") String userType,
                                                @RequestParam(name = "userId", defaultValue = "") String userId,
                                                @RequestParam(name = "account_code", defaultValue = "") String account_code) {
        WXBind bean = new WXBind();
        param = "encryptedData=" + encryptedData + ",iv=" + iv + ",signature=" + signature + ",hasUserInfo=" + hasUserInfo + ",openid=" + openid + ",rawData=" + rawData + ",wx_type=" + wx_type + ",userType=" + userType + ",userId=" + userId + ",account_code=" + account_code;
        try {
            //授权状态为false 进行数据解密并存库
            if (hasUserInfo) {
                startTime = System.currentTimeMillis();
                String session_key = redisUtil.get(openid).toString();
                //解密
                String decryptStr = AesCbcUtil.decrypt(encryptedData, session_key, iv, "UTF-8");
                //计算SHA1摘要
                String encryptStr = SecureUtil.sha1().digestHex(rawData + session_key);
                log.info("SHA1摘要{}",encryptStr);
                if (encryptStr.equals(signature)) {
                    WxAuthRequestBean.UserInfo userInfo = JSON.parseObject(decryptStr, WxAuthRequestBean.UserInfo.class);
                    //更新微信用户信息
                    userInfo.setOpenid(openid);
                    bean = apiBeanUtil.wxUserInfoDeal(wx_type, userType, userInfo, account_code);
                    log.info("数据没有被篡改-数据更新");
                } else {
                    log.info("数据被篡改-未更新");
                    bean.error("decrypt fail data tampered");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            errorMsg = e.getMessage();
            bean.error(ApiCodeConts.MESSAGE_ERROR);
        }
        //耗时
        timeConsuming = String.valueOf(System.currentTimeMillis() - startTime);
        //响应的内容
        beanStr = JSON.toJSONString(bean);
        //存日志
        apiBeanUtil.putLog(bean.getLog_id(), timeConsuming, beanStr, ip, param, requestURI, errorMsg, LogTypeConts.WX_OAUTH_DECRYPT, userId, userAgent);
        return new ResponseEntity<Object>(beanStr, httpHeaders, HttpStatus.OK);
    }

    /**
     * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
     * @param iv            加密算法的初始向量
     * @param session_key   获取得到的session_key 不为空wx.login调用code2Session得到
     * @return org.springframework.http.ResponseEntity<java.lang.Object>
     * @Description 解密手机号信息
     * @Author 小帅丶
     * @Date 2020年4月1日18:11:01
     **/
    @RequestMapping(value = "/v1/decrypt/phone", method = {RequestMethod.POST})
    public ResponseEntity<Object> wxDecryptInfoByPhone(@RequestParam(name = "encryptedData", defaultValue = "", required = false) String encryptedData,
                                                       @RequestParam(name = "iv", defaultValue = "") String iv,
                                                       @RequestParam(name = "session_key", defaultValue = "false") String session_key) {
        WxLoginResponseBean bean = new WxLoginResponseBean();
        try {
            //解密
            String decryptStr = AesCbcUtil.decrypt(encryptedData, session_key, iv, "UTF-8");
            System.out.println(JSON.toJSONString(decryptStr));
        } catch (Exception e) {
            log.info(requestURI + "出错了异常信息{}", e.getMessage());
            bean.error("system error");
        }
        return new ResponseEntity<Object>(bean, httpHeaders, HttpStatus.OK);
    }

    /**
     * @Description 获取用户首次访问累计天数
     * @Author 小帅丶
     * @return org.springframework.http.ResponseEntity<java.lang.Object>
     * @Date 2020年9月22日11:46:30
     **/
    @RequestMapping(value = "/v1/days", method = {RequestMethod.GET})
    public ResponseEntity<Object> getDays() {
        WxLoginResponseBean bean = new WxLoginResponseBean();
        String openid = ServletRequestUtils.getStringParameter(request, "openid","");
        try {
            startTime = System.currentTimeMillis();
            param = "userId="+userId+",openid="+openid;
            if(oConvertUtils.isEmpty(openid)||oConvertUtils.isEmpty(userId)){
                bean.fail("参数缺失，请检查",410101);
            }else{
                LambdaQueryWrapper<LiteUserInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(LiteUserInfo::getUserId, userId);
                LiteUserInfo liteUserInfoDB = userInfoService.getOne(queryWrapper);
                if(null==liteUserInfoDB){
                    bean.fail("此用户不存在",410501);
                } else {
                    if(liteUserInfoDB.getOpenid().equals(openid)){
                        WxLoginResponseBean.Data data = new WxLoginResponseBean.Data();
                        data.setDays(liteUserInfoDB.getDays());
                        bean.success("查询成功",data);
                    } else {
                        bean.fail("用户信息不匹配",410502);
                    }
                }
            }
        } catch (Exception e) {
            log.info(requestURI + "出错了异常信息{}", e.getMessage());
            bean.error("system error");
        }
        //耗时
        timeConsuming = String.valueOf(System.currentTimeMillis() - startTime);
        //响应的内容
        beanStr = JSON.toJSONString(bean);
        //存日志
        apiBeanUtil.putLog(bean.getLog_id(), timeConsuming, beanStr, ip, param,requestURI, errorMsg, LogTypeConts.USER_DAYS,userId,userAgent);
        return new ResponseEntity<Object>(beanStr, httpHeaders, HttpStatus.OK);
    }

}
